<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Changing the contrast and brightness of an image!</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d9/df8/tutorial_root.html">OpenCV Tutorials</a></li><li class="navelem"><a class="el" href="../../de/d7a/tutorial_table_of_content_core.html">The Core Functionality (core module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Changing the contrast and brightness of an image! </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Prev Tutorial:</b> <a class="el" href="../../d5/dc4/tutorial_adding_images.html">Adding (blending) two images using OpenCV</a></p>
<p><b>Next Tutorial:</b> <a class="el" href="../../d8/d01/tutorial_discrete_fourier_transform.html">Discrete Fourier Transform</a></p>
<table class="doxtable">
<tr>
<th align="right"></th><th align="left"></th></tr>
<tr>
<td align="right">Original author </td><td align="left">Ana Huamán </td></tr>
<tr>
<td align="right">Compatibility </td><td align="left">OpenCV &gt;= 3.0 </td></tr>
</table>
<h2>Goal </h2>
<p>In this tutorial you will learn how to:</p>
<ul>
<li>Access pixel values</li>
<li>Initialize a matrix with zeros</li>
<li>Learn what <a class="el" href="../../db/de0/group__core__utils.html#gab93126370b85fda2c8bfaf8c811faeaf">cv::saturate_cast</a> does and why it is useful</li>
<li>Get some cool info about pixel transformations</li>
<li>Improve the brightness of an image on a practical example</li>
</ul>
<h2>Theory </h2>
<dl class="section note"><dt>Note</dt><dd>The explanation below belongs to the book <a href="http://szeliski.org/Book/">Computer Vision: Algorithms and Applications</a> by Richard Szeliski</dd></dl>
<h3>Image Processing</h3>
<ul>
<li>A general image processing operator is a function that takes one or more input images and produces an output image.</li>
<li>Image transforms can be seen as:<ul>
<li>Point operators (pixel transforms)</li>
<li>Neighborhood (area-based) operators</li>
</ul>
</li>
</ul>
<h3>Pixel Transforms</h3>
<ul>
<li>In this kind of image processing transform, each output pixel's value depends on only the corresponding input pixel value (plus, potentially, some globally collected information or parameters).</li>
<li>Examples of such operators include <em>brightness and contrast adjustments</em> as well as color correction and transformations.</li>
</ul>
<h3>Brightness and contrast adjustments</h3>
<ul>
<li><p class="startli">Two commonly used point processes are <em>multiplication</em> and <em>addition</em> with a constant:</p>
<p class="formulaDsp">
\[g(x) = \alpha f(x) + \beta\]
</p>
</li>
<li>The parameters \(\alpha &gt; 0\) and \(\beta\) are often called the <em>gain</em> and <em>bias</em> parameters; sometimes these parameters are said to control <em>contrast</em> and <em>brightness</em> respectively.</li>
<li><p class="startli">You can think of \(f(x)\) as the source image pixels and \(g(x)\) as the output image pixels. Then, more conveniently we can write the expression as:</p>
<p class="formulaDsp">
\[g(i,j) = \alpha \cdot f(i,j) + \beta\]
</p>
<p class="startli">where \(i\) and \(j\) indicates that the pixel is located in the <em>i-th</em> row and <em>j-th</em> column.</p>
</li>
</ul>
<h2>Code </h2>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp">here</a></li>
<li>The following code performs the operation \(g(i,j) = \alpha \cdot f(i,j) + \beta\) : <div class="fragment"><div class="line"></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d6/d87/imgcodecs_8hpp.html">opencv2/imgcodecs.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d4/dd5/highgui_8hpp.html">opencv2/highgui.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"></div><div class="line"><span class="comment">// we&#39;re NOT &quot;using namespace std;&quot; here, to avoid collisions between the beta variable and std::beta in c++17</span></div><div class="line"><span class="keyword">using</span> std::cin;</div><div class="line"><span class="keyword">using</span> std::cout;</div><div class="line"><span class="keyword">using</span> std::endl;</div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d2/d75/namespacecv.html">cv</a>;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main( <span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>** argv )</div><div class="line">{</div><div class="line">    <a class="code" href="../../d0/d2e/classcv_1_1CommandLineParser.html">CommandLineParser</a> parser( argc, argv, <span class="stringliteral">&quot;{@input | lena.jpg | input image}&quot;</span> );</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> image = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;( <span class="stringliteral">&quot;@input&quot;</span> ) ) );</div><div class="line">    <span class="keywordflow">if</span>( image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>() )</div><div class="line">    {</div><div class="line">      cout &lt;&lt; <span class="stringliteral">&quot;Could not open or find the image!\n&quot;</span> &lt;&lt; endl;</div><div class="line">      cout &lt;&lt; <span class="stringliteral">&quot;Usage: &quot;</span> &lt;&lt; argv[0] &lt;&lt; <span class="stringliteral">&quot; &lt;Input image&gt;&quot;</span> &lt;&lt; endl;</div><div class="line">      <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> new_image = <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>( image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#af2d2652e552d7de635988f18a84b53e5">type</a>() );</div><div class="line"></div><div class="line">    <span class="keywordtype">double</span> alpha = 1.0; <span class="comment">/*&lt; Simple contrast control */</span></div><div class="line">    <span class="keywordtype">int</span> beta = 0;       <span class="comment">/*&lt; Simple brightness control */</span></div><div class="line"></div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot; Basic Linear Transforms &quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;-------------------------&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;* Enter the alpha value [1.0-3.0]: &quot;</span>; cin &gt;&gt; alpha;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;* Enter the beta value [0-100]: &quot;</span>;    cin &gt;&gt; beta;</div><div class="line"></div><div class="line">    <span class="keywordflow">for</span>( <span class="keywordtype">int</span> y = 0; y &lt; image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a>; y++ ) {</div><div class="line">        <span class="keywordflow">for</span>( <span class="keywordtype">int</span> x = 0; x &lt; image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a>; x++ ) {</div><div class="line">            <span class="keywordflow">for</span>( <span class="keywordtype">int</span> c = 0; c &lt; image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa11336b9ac538e0475d840657ce164be">channels</a>(); c++ ) {</div><div class="line">                new_image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa5d20fc86d41d59e4d71ae93daee9726">at</a>&lt;<a class="code" href="../../d6/dcf/classcv_1_1Vec.html">Vec3b</a>&gt;(y,x)[c] =</div><div class="line">                  <a class="code" href="../../db/de0/group__core__utils.html#ga2858f5fe522e46a2e17662669199f6ff">saturate_cast&lt;uchar&gt;</a>( alpha*image.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa5d20fc86d41d59e4d71ae93daee9726">at</a>&lt;<a class="code" href="../../d6/dcf/classcv_1_1Vec.html">Vec3b</a>&gt;(y,x)[c] + beta );</div><div class="line">            }</div><div class="line">        }</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;Original Image&quot;</span>, image);</div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;New Image&quot;</span>, new_image);</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">waitKey</a>();</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment -->  </div> </li>
</ul>
 <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java">here</a></li>
<li>The following code performs the operation \(g(i,j) = \alpha \cdot f(i,j) + \beta\) : <div class="fragment"><div class="line"><span class="keyword">import</span> java.util.Scanner;</div><div class="line"></div><div class="line"><span class="keyword">import</span> org.opencv.core.Core;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Mat;</div><div class="line"><span class="keyword">import</span> org.opencv.highgui.HighGui;</div><div class="line"><span class="keyword">import</span> org.opencv.imgcodecs.Imgcodecs;</div><div class="line"></div><div class="line"><span class="keyword">class </span>BasicLinearTransforms {</div><div class="line">    <span class="keyword">private</span> byte <a class="code" href="../../d6/d7d/namespacecv_1_1gapi_1_1own.html#a731d72310c89b732dcba8248d7b600b1">saturate</a>(<span class="keywordtype">double</span> val) {</div><div class="line">        <span class="keywordtype">int</span> iVal = (int) Math.round(val);</div><div class="line">        iVal = iVal &gt; 255 ? 255 : (iVal &lt; 0 ? 0 : iVal);</div><div class="line">        <span class="keywordflow">return</span> (byte) iVal;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">public</span> <span class="keywordtype">void</span> run(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> imagePath = args.length &gt; 0 ? args[0] : <span class="stringliteral">&quot;../data/lena.jpg&quot;</span>;</div><div class="line">        Mat image = Imgcodecs.imread(imagePath);</div><div class="line">        <span class="keywordflow">if</span> (image.empty()) {</div><div class="line">            System.out.println(<span class="stringliteral">&quot;Empty image: &quot;</span> + imagePath);</div><div class="line">            System.exit(0);</div><div class="line">        }</div><div class="line"></div><div class="line">        Mat newImage = Mat.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">zeros</a>(image.size(), image.type());</div><div class="line"></div><div class="line">        <span class="keywordtype">double</span> alpha = 1.0; <span class="comment">/*&lt; Simple contrast control */</span></div><div class="line">        <span class="keywordtype">int</span> beta = 0;       <span class="comment">/*&lt; Simple brightness control */</span></div><div class="line"></div><div class="line">        System.out.println(<span class="stringliteral">&quot; Basic Linear Transforms &quot;</span>);</div><div class="line">        System.out.println(<span class="stringliteral">&quot;-------------------------&quot;</span>);</div><div class="line">        <span class="keywordflow">try</span> (Scanner scanner = <span class="keyword">new</span> Scanner(System.in)) {</div><div class="line">            System.out.print(<span class="stringliteral">&quot;* Enter the alpha value [1.0-3.0]: &quot;</span>);</div><div class="line">            alpha = scanner.nextDouble();</div><div class="line">            System.out.print(<span class="stringliteral">&quot;* Enter the beta value [0-100]: &quot;</span>);</div><div class="line">            beta = scanner.nextInt();</div><div class="line">        }</div><div class="line"></div><div class="line">        byte[] imageData = <span class="keyword">new</span> byte[(int) (image.total()*image.channels())];</div><div class="line">        image.get(0, 0, imageData);</div><div class="line">        byte[] newImageData = <span class="keyword">new</span> byte[(int) (newImage.total()*newImage.channels())];</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y = 0; y &lt; image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a883ccff445b70d8c5673612fcea63374">rows</a>(); y++) {</div><div class="line">            <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x = 0; x &lt; image.cols(); x++) {</div><div class="line">                <span class="keywordflow">for</span> (<span class="keywordtype">int</span> c = 0; c &lt; image.channels(); c++) {</div><div class="line">                    <span class="keywordtype">double</span> pixelValue = imageData[(y * image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a0be112b36f43fbfe06e8f9d1361f51b6">cols</a>() + x) * image.channels() + c];</div><div class="line">                    pixelValue = pixelValue &lt; 0 ? pixelValue + 256 : pixelValue;</div><div class="line">                    newImageData[(y * image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a0be112b36f43fbfe06e8f9d1361f51b6">cols</a>() + x) * image.channels() + c]</div><div class="line">                            = <a class="code" href="../../d6/d7d/namespacecv_1_1gapi_1_1own.html#a731d72310c89b732dcba8248d7b600b1">saturate</a>(alpha * pixelValue + beta);</div><div class="line">                }</div><div class="line">            }</div><div class="line">        }</div><div class="line">        newImage.put(0, 0, newImageData);</div><div class="line"></div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;Original Image&quot;</span>, image);</div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;New Image&quot;</span>, newImage);</div><div class="line"></div><div class="line">        HighGui.waitKey();</div><div class="line">        System.exit(0);</div><div class="line">    }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="keyword">class </span>BasicLinearTransformsDemo {</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keywordtype">void</span> main(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <span class="comment">// Load the native OpenCV library</span></div><div class="line">        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);</div><div class="line"></div><div class="line">        <span class="keyword">new</span> BasicLinearTransforms().run(args);</div><div class="line">    }</div><div class="line">}</div></div><!-- fragment -->  </div> </li>
</ul>
 <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py">here</a></li>
<li>The following code performs the operation \(g(i,j) = \alpha \cdot f(i,j) + \beta\) : <div class="fragment"><div class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> print_function</div><div class="line"><span class="keyword">from</span> builtins <span class="keyword">import</span> input</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> argparse</div><div class="line"></div><div class="line"><span class="comment"># Read image given by user</span></div><div class="line"></div><div class="line">parser = argparse.ArgumentParser(description=<span class="stringliteral">&#39;Code for Changing the contrast and brightness of an image! tutorial.&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input&#39;</span>, help=<span class="stringliteral">&#39;Path to input image.&#39;</span>, default=<span class="stringliteral">&#39;lena.jpg&#39;</span>)</div><div class="line">args = parser.parse_args()</div><div class="line"></div><div class="line">image = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input))</div><div class="line"><span class="keywordflow">if</span> image <span class="keywordflow">is</span> <span class="keywordtype">None</span>:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Could not open or find the image: &#39;</span>, args.input)</div><div class="line">    exit(0)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">new_image = np.zeros(image.shape, image.dtype)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">alpha = 1.0 <span class="comment"># Simple contrast control</span></div><div class="line">beta = 0    <span class="comment"># Simple brightness control</span></div><div class="line"></div><div class="line"><span class="comment"># Initialize values</span></div><div class="line"><a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39; Basic Linear Transforms &#39;</span>)</div><div class="line"><a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;-------------------------&#39;</span>)</div><div class="line"><span class="keywordflow">try</span>:</div><div class="line">    alpha = float(input(<span class="stringliteral">&#39;* Enter the alpha value [1.0-3.0]: &#39;</span>))</div><div class="line">    beta = int(input(<span class="stringliteral">&#39;* Enter the beta value [0-100]: &#39;</span>))</div><div class="line"><span class="keywordflow">except</span> ValueError:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Error, not a number&#39;</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># Do the operation new_image(i,j) = alpha*image(i,j) + beta</span></div><div class="line"><span class="comment"># Instead of these &#39;for&#39; loops we could have used simply:</span></div><div class="line"><span class="comment"># new_image = cv.convertScaleAbs(image, alpha=alpha, beta=beta)</span></div><div class="line"><span class="comment"># but we wanted to show you how to access the pixels :)</span></div><div class="line"></div><div class="line"><span class="keywordflow">for</span> y <span class="keywordflow">in</span> range(image.shape[0]):</div><div class="line">    <span class="keywordflow">for</span> x <span class="keywordflow">in</span> range(image.shape[1]):</div><div class="line">        <span class="keywordflow">for</span> c <span class="keywordflow">in</span> range(image.shape[2]):</div><div class="line">            new_image[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;Original Image&#39;</span>, image)</div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;New Image&#39;</span>, new_image)</div><div class="line"></div><div class="line"><span class="comment"># Wait until user press some key</span></div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>()</div><div class="line"></div></div><!-- fragment -->  </div> </li>
</ul>
<h2>Explanation </h2>
<ul>
<li>We load an image using <a class="el" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv::imread</a> and save it in a Mat object:</li>
</ul>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    CommandLineParser parser( argc, argv, <span class="stringliteral">&quot;{@input | lena.jpg | input image}&quot;</span> );</div><div class="line">    Mat image = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;( <span class="stringliteral">&quot;@input&quot;</span> ) ) );</div><div class="line">    <span class="keywordflow">if</span>( image.empty() )</div><div class="line">    {</div><div class="line">      cout &lt;&lt; <span class="stringliteral">&quot;Could not open or find the image!\n&quot;</span> &lt;&lt; endl;</div><div class="line">      cout &lt;&lt; <span class="stringliteral">&quot;Usage: &quot;</span> &lt;&lt; argv[0] &lt;&lt; <span class="stringliteral">&quot; &lt;Input image&gt;&quot;</span> &lt;&lt; endl;</div><div class="line">      <span class="keywordflow">return</span> -1;</div><div class="line">    }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> imagePath = args.length &gt; 0 ? args[0] : <span class="stringliteral">&quot;../data/lena.jpg&quot;</span>;</div><div class="line">        Mat image = Imgcodecs.imread(imagePath);</div><div class="line">        <span class="keywordflow">if</span> (image.empty()) {</div><div class="line">            System.out.println(<span class="stringliteral">&quot;Empty image: &quot;</span> + imagePath);</div><div class="line">            System.exit(0);</div><div class="line">        }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">parser = argparse.ArgumentParser(description=<span class="stringliteral">&#39;Code for Changing the contrast and brightness of an image! tutorial.&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input&#39;</span>, help=<span class="stringliteral">&#39;Path to input image.&#39;</span>, default=<span class="stringliteral">&#39;lena.jpg&#39;</span>)</div><div class="line">args = parser.parse_args()</div><div class="line"></div><div class="line">image = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input))</div><div class="line"><span class="keywordflow">if</span> image <span class="keywordflow">is</span> <span class="keywordtype">None</span>:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Could not open or find the image: &#39;</span>, args.input)</div><div class="line">    exit(0)</div></div><!-- fragment --> </div> <ul>
<li>Now, since we will make some transformations to this image, we need a new Mat object to store it. Also, we want this to have the following features:<ul>
<li>Initial pixel values equal to zero</li>
<li>Same size and type as the original image</li>
</ul>
</li>
</ul>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    Mat new_image = Mat::zeros( image.size(), image.type() );</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        Mat newImage = Mat.zeros(image.size(), image.type());</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">new_image = np.zeros(image.shape, image.dtype)</div></div><!-- fragment --> </div> <p>We observe that <a class="el" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">cv::Mat::zeros</a> returns a Matlab-style zero initializer based on <em><a class="el" href="../../df/d5b/namespacecv_1_1gapi_1_1streaming.html#a0a915e69f4cc8284293e40fc9ffbf157" title="Gets dimensions from Mat. ">image.size()</a></em> and <em>image.type()</em></p>
<ul>
<li>We ask now the values of \(\alpha\) and \(\beta\) to be entered by the user:</li>
</ul>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="keywordtype">double</span> alpha = 1.0; <span class="comment">/*&lt; Simple contrast control */</span></div><div class="line">    <span class="keywordtype">int</span> beta = 0;       <span class="comment">/*&lt; Simple brightness control */</span></div><div class="line"></div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot; Basic Linear Transforms &quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;-------------------------&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;* Enter the alpha value [1.0-3.0]: &quot;</span>; cin &gt;&gt; alpha;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;* Enter the beta value [0-100]: &quot;</span>;    cin &gt;&gt; beta;</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="keywordtype">double</span> alpha = 1.0; <span class="comment">/*&lt; Simple contrast control */</span></div><div class="line">        <span class="keywordtype">int</span> beta = 0;       <span class="comment">/*&lt; Simple brightness control */</span></div><div class="line"></div><div class="line">        System.out.println(<span class="stringliteral">&quot; Basic Linear Transforms &quot;</span>);</div><div class="line">        System.out.println(<span class="stringliteral">&quot;-------------------------&quot;</span>);</div><div class="line">        <span class="keywordflow">try</span> (Scanner scanner = <span class="keyword">new</span> Scanner(System.in)) {</div><div class="line">            System.out.print(<span class="stringliteral">&quot;* Enter the alpha value [1.0-3.0]: &quot;</span>);</div><div class="line">            alpha = scanner.nextDouble();</div><div class="line">            System.out.print(<span class="stringliteral">&quot;* Enter the beta value [0-100]: &quot;</span>);</div><div class="line">            beta = scanner.nextInt();</div><div class="line">        }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">alpha = 1.0 <span class="comment"># Simple contrast control</span></div><div class="line">beta = 0    <span class="comment"># Simple brightness control</span></div><div class="line"></div><div class="line"><span class="comment"># Initialize values</span></div><div class="line"><a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39; Basic Linear Transforms &#39;</span>)</div><div class="line"><a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;-------------------------&#39;</span>)</div><div class="line"><span class="keywordflow">try</span>:</div><div class="line">    alpha = float(input(<span class="stringliteral">&#39;* Enter the alpha value [1.0-3.0]: &#39;</span>))</div><div class="line">    beta = int(input(<span class="stringliteral">&#39;* Enter the beta value [0-100]: &#39;</span>))</div><div class="line"><span class="keywordflow">except</span> ValueError:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Error, not a number&#39;</span>)</div></div><!-- fragment --> </div> <ul>
<li>Now, to perform the operation \(g(i,j) = \alpha \cdot f(i,j) + \beta\) we will access to each pixel in image. Since we are operating with BGR images, we will have three values per pixel (B, G and R), so we will also access them separately. Here is the piece of code:</li>
</ul>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="keywordflow">for</span>( <span class="keywordtype">int</span> y = 0; y &lt; image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a883ccff445b70d8c5673612fcea63374">rows</a>; y++ ) {</div><div class="line">        <span class="keywordflow">for</span>( <span class="keywordtype">int</span> x = 0; x &lt; image.cols; x++ ) {</div><div class="line">            <span class="keywordflow">for</span>( <span class="keywordtype">int</span> c = 0; c &lt; image.channels(); c++ ) {</div><div class="line">                new_image.at&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga7e6060c0b8d48459964df6e1eb524c03">Vec3b</a>&gt;(y,x)[c] =</div><div class="line">                  <a class="code" href="../../db/de0/group__core__utils.html#ga2858f5fe522e46a2e17662669199f6ff">saturate_cast&lt;uchar&gt;</a>( alpha*image.at&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga7e6060c0b8d48459964df6e1eb524c03">Vec3b</a>&gt;(y,x)[c] + beta );</div><div class="line">            }</div><div class="line">        }</div><div class="line">    }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        byte[] imageData = <span class="keyword">new</span> byte[(int) (image.total()*image.channels())];</div><div class="line">        image.get(0, 0, imageData);</div><div class="line">        byte[] newImageData = <span class="keyword">new</span> byte[(int) (newImage.total()*newImage.channels())];</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y = 0; y &lt; image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a883ccff445b70d8c5673612fcea63374">rows</a>(); y++) {</div><div class="line">            <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x = 0; x &lt; image.cols(); x++) {</div><div class="line">                <span class="keywordflow">for</span> (<span class="keywordtype">int</span> c = 0; c &lt; image.channels(); c++) {</div><div class="line">                    <span class="keywordtype">double</span> pixelValue = imageData[(y * image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a0be112b36f43fbfe06e8f9d1361f51b6">cols</a>() + x) * image.channels() + c];</div><div class="line">                    pixelValue = pixelValue &lt; 0 ? pixelValue + 256 : pixelValue;</div><div class="line">                    newImageData[(y * image.<a class="code" href="../../de/de1/classcv_1_1Matx.html#a5a5955a6d8274a374aa637b21272f3a3a0be112b36f43fbfe06e8f9d1361f51b6">cols</a>() + x) * image.channels() + c]</div><div class="line">                            = <a class="code" href="../../d6/d7d/namespacecv_1_1gapi_1_1own.html#a731d72310c89b732dcba8248d7b600b1">saturate</a>(alpha * pixelValue + beta);</div><div class="line">                }</div><div class="line">            }</div><div class="line">        }</div><div class="line">        newImage.put(0, 0, newImageData);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line"><span class="keywordflow">for</span> y <span class="keywordflow">in</span> range(image.shape[0]):</div><div class="line">    <span class="keywordflow">for</span> x <span class="keywordflow">in</span> range(image.shape[1]):</div><div class="line">        <span class="keywordflow">for</span> c <span class="keywordflow">in</span> range(image.shape[2]):</div><div class="line">            new_image[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255)</div></div><!-- fragment --> </div> <p>Notice the following (<b>C++ code only</b>):</p><ul>
<li>To access each pixel in the images we are using this syntax: <em>image.at&lt;Vec3b&gt;(y,x)[c]</em> where <em>y</em> is the row, <em>x</em> is the column and <em>c</em> is B, G or R (0, 1 or 2).</li>
<li>Since the operation \(\alpha \cdot p(i,j) + \beta\) can give values out of range or not integers (if \(\alpha\) is float), we use <a class="el" href="../../db/de0/group__core__utils.html#gab93126370b85fda2c8bfaf8c811faeaf" title="Template function for accurate conversion from one primitive type to another. ">cv::saturate_cast</a> to make sure the values are valid.</li>
<li>Finally, we create windows and show the images, the usual way.</li>
</ul>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;Original Image&quot;</span>, image);</div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;New Image&quot;</span>, new_image);</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">waitKey</a>();</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;Original Image&quot;</span>, image);</div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;New Image&quot;</span>, newImage);</div><div class="line"></div><div class="line">        HighGui.waitKey();</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line"><span class="comment"># Show stuff</span></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;Original Image&#39;</span>, image)</div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;New Image&#39;</span>, new_image)</div><div class="line"></div><div class="line"><span class="comment"># Wait until user press some key</span></div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>()</div></div><!-- fragment --> </div> <dl class="section note"><dt>Note</dt><dd>Instead of using the <b>for</b> loops to access each pixel, we could have simply used this command:</dd></dl>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">image.convertTo(new_image, -1, alpha, beta);</div></div><!-- fragment -->  </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">image.convertTo(newImage, -1, alpha, beta);</div></div><!-- fragment -->  </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">new_image = <a class="code" href="../../d2/de8/group__core__array.html#ga3460e9c9f37b563ab9dd550c4d8c4e7d">cv.convertScaleAbs</a>(image, alpha=alpha, beta=beta)</div></div><!-- fragment -->  </div> <p>where <a class="el" href="../../d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b">cv::Mat::convertTo</a> would effectively perform *new_image = a*image + beta*. However, we wanted to show you how to access each pixel. In any case, both methods give the same result but convertTo is more optimized and works a lot faster.</p>
<h2>Result </h2>
<ul>
<li>Running our code and using \(\alpha = 2.2\) and \(\beta = 50\) <div class="fragment"><div class="line">$ ./BasicLinearTransforms lena.jpg</div><div class="line">Basic Linear Transforms</div><div class="line">-------------------------</div><div class="line">* Enter the alpha value [1.0-3.0]: 2.2</div><div class="line">* Enter the beta value [0-100]: 50</div></div><!-- fragment --></li>
<li><p class="startli">We get this:</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_Result_big.jpg" alt="Basic_Linear_Transform_Tutorial_Result_big.jpg"/>
</div>
</li>
</ul>
<h2>Practical example </h2>
<p>In this paragraph, we will put into practice what we have learned to correct an underexposed image by adjusting the brightness and the contrast of the image. We will also see another technique to correct the brightness of an image called gamma correction.</p>
<h3>Brightness and contrast adjustments</h3>
<p>Increasing (/ decreasing) the \(\beta\) value will add (/ subtract) a constant value to every pixel. Pixel values outside of the [0 ; 255] range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamped to 255 (/ 0)).</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_hist_beta.png" alt="Basic_Linear_Transform_Tutorial_hist_beta.png"/>
<div class="caption">
In light gray, histogram of the original image, in dark gray when brightness = 80 in Gimp</div></div>
<p> The histogram represents for each color level the number of pixels with that color level. A dark image will have many pixels with low color value and thus the histogram will present a peak in its left part. When adding a constant bias, the histogram is shifted to the right as we have added a constant bias to all the pixels.</p>
<p>The \(\alpha\) parameter will modify how the levels spread. If \( \alpha &lt; 1 \), the color levels will be compressed and the result will be an image with less contrast.</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_hist_alpha.png" alt="Basic_Linear_Transform_Tutorial_hist_alpha.png"/>
<div class="caption">
In light gray, histogram of the original image, in dark gray when contrast &lt; 0 in Gimp</div></div>
<p> Note that these histograms have been obtained using the Brightness-Contrast tool in the Gimp software. The brightness tool should be identical to the \(\beta\) bias parameters but the contrast tool seems to differ to the \(\alpha\) gain where the output range seems to be centered with Gimp (as you can notice in the previous histogram).</p>
<p>It can occur that playing with the \(\beta\) bias will improve the brightness but in the same time the image will appear with a slight veil as the contrast will be reduced. The \(\alpha\) gain can be used to diminue this effect but due to the saturation, we will lose some details in the original bright regions.</p>
<h3>Gamma correction</h3>
<p><a href="https://en.wikipedia.org/wiki/Gamma_correction">Gamma correction</a> can be used to correct the brightness of an image by using a non linear transformation between the input values and the mapped output values:</p>
<p class="formulaDsp">
\[O = \left( \frac{I}{255} \right)^{\gamma} \times 255\]
</p>
<p>As this relation is non linear, the effect will not be the same for all the pixels and will depend to their original value.</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_gamma.png" alt="Basic_Linear_Transform_Tutorial_gamma.png"/>
<div class="caption">
Plot for different values of gamma</div></div>
<p> When \( \gamma &lt; 1 \), the original dark regions will be brighter and the histogram will be shifted to the right whereas it will be the opposite with \( \gamma &gt; 1 \).</p>
<h3>Correct an underexposed image</h3>
<p>The following image has been corrected with: \( \alpha = 1.3 \) and \( \beta = 40 \).</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_linear_transform_correction.jpg" alt="Basic_Linear_Transform_Tutorial_linear_transform_correction.jpg"/>
<div class="caption">
By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons</div></div>
<p> The overall brightness has been improved but you can notice that the clouds are now greatly saturated due to the numerical saturation of the implementation used (<a href="https://en.wikipedia.org/wiki/Clipping_(photography)">highlight clipping</a> in photography).</p>
<p>The following image has been corrected with: \( \gamma = 0.4 \).</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_gamma_correction.jpg" alt="Basic_Linear_Transform_Tutorial_gamma_correction.jpg"/>
<div class="caption">
By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons</div></div>
<p> The gamma correction should tend to add less saturation effect as the mapping is non linear and there is no numerical saturation possible as in the previous method.</p>
<div class="image">
<img src="../../Basic_Linear_Transform_Tutorial_histogram_compare.png" alt="Basic_Linear_Transform_Tutorial_histogram_compare.png"/>
<div class="caption">
Left: histogram after alpha, beta correction ; Center: histogram of the original image ; Right: histogram after the gamma correction</div></div>
<p> The previous figure compares the histograms for the three images (the y-ranges are not the same between the three histograms). You can notice that most of the pixel values are in the lower part of the histogram for the original image. After \( \alpha \), \( \beta \) correction, we can observe a big peak at 255 due to the saturation as well as a shift in the right. After gamma correction, the histogram is shifted to the right but the pixels in the dark regions are more shifted (see the gamma curves <a href="../../Basic_Linear_Transform_Tutorial_gamma.png">figure</a>) than those in the bright regions.</p>
<p>In this tutorial, you have seen two simple methods to adjust the contrast and the brightness of an image. <b>They are basic techniques and are not intended to be used as a replacement of a raster graphics editor!</b></p>
<h3>Code</h3>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'><p> Code for the tutorial is <a href="https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/ImgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.cpp">here</a>. </p> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'><p> Code for the tutorial is <a href="https://github.com/opencv/opencv/blob/master/samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/ChangingContrastBrightnessImageDemo.java">here</a>. </p> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'><p> Code for the tutorial is <a href="https://github.com/opencv/opencv/blob/master/samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.py">here</a>. </p> </div> <p>Code for the gamma correction:</p>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    Mat lookUpTable(1, 256, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga32b18d904ee2b1731a9416a8eef67d06">CV_8U</a>);</div><div class="line">    <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga65f85814a8290f9797005d3b28e7e5fc">uchar</a>* p = lookUpTable.ptr();</div><div class="line">    <span class="keywordflow">for</span>( <span class="keywordtype">int</span> i = 0; i &lt; 256; ++i)</div><div class="line">        p[i] = <a class="code" href="../../db/de0/group__core__utils.html#ga2858f5fe522e46a2e17662669199f6ff">saturate_cast&lt;uchar&gt;</a>(<a class="code" href="../../d7/dcc/group__core__utils__softfloat.html#ga8bc36646a43b82baa15f151a973fb0c5">pow</a>(i / 255.0, gamma_) * 255.0);</div><div class="line"></div><div class="line">    Mat res = img.clone();</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gab55b8d062b7f5587720ede032d34156f">LUT</a>(img, lookUpTable, res);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        Mat lookUpTable = <span class="keyword">new</span> Mat(1, 256, CvType.CV_8U);</div><div class="line">        byte[] lookUpTableData = <span class="keyword">new</span> byte[(int) (lookUpTable.total()*lookUpTable.channels())];</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; lookUpTable.cols(); i++) {</div><div class="line">            lookUpTableData[i] = <a class="code" href="../../d6/d7d/namespacecv_1_1gapi_1_1own.html#a731d72310c89b732dcba8248d7b600b1">saturate</a>(Math.pow(i / 255.0, gammaValue) * 255.0);</div><div class="line">        }</div><div class="line">        lookUpTable.put(0, 0, lookUpTableData);</div><div class="line">        Mat img = <span class="keyword">new</span> Mat();</div><div class="line">        Core.LUT(matImgSrc, lookUpTable, img);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">    lookUpTable = np.empty((1,256), np.uint8)</div><div class="line">    <span class="keywordflow">for</span> i <span class="keywordflow">in</span> range(256):</div><div class="line">        lookUpTable[0,i] = np.clip(<a class="code" href="../../d7/dcc/group__core__utils__softfloat.html#ga8bc36646a43b82baa15f151a973fb0c5">pow</a>(i / 255.0, gamma) * 255.0, 0, 255)</div><div class="line"></div><div class="line">    res = <a class="code" href="../../d2/de8/group__core__array.html#gab55b8d062b7f5587720ede032d34156f">cv.LUT</a>(img_original, lookUpTable)</div></div><!-- fragment --> </div> <p>A look-up table is used to improve the performance of the computation as only 256 values needs to be calculated once.</p>
<h3>Additional resources</h3>
<ul>
<li><a href="https://learnopengl.com/#!Advanced-Lighting/Gamma-Correction">Gamma correction in graphics rendering</a></li>
<li><a href="http://www.graphics.cornell.edu/~westin/gamma/gamma.html">Gamma correction and images displayed on CRT monitors</a></li>
<li><a href="http://www.cambridgeincolour.com/tutorials/digital-exposure-techniques.htm">Digital exposure techniques</a> </li>
</ul>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:34 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
